use nix::fcntl::{open, OFlag};
use nix::libc::{__errno_location, c_int, chdir, clone, execlp, execvp, exit, malloc, mkdir, mount, printf, rmdir, setenv, setns, strerror, umount2, wait, CLONE_NEWIPC, CLONE_NEWNET, CLONE_NEWNS, CLONE_NEWPID, CLONE_NEWUTS, MNT_DETACH, MS_BIND, MS_MGC_VAL, MS_NODEV, MS_NOEXEC, MS_NOSUID, MS_PRIVATE, MS_REC, SIGCHLD};
use nix::sys::stat::Mode;
use nix::unistd::{close, dup2, pivot_root};
use std::env::args;
use std::ffi::{c_void, CString};
use std::fs;
use std::fs::{exists, OpenOptions};
use std::io::{Read, Write};
use std::mem::transmute;
use std::process::Command;
use std::ptr::{null, null_mut};
use std::thread::sleep;
fn main() {
    unsafe {
        let child_stack_space = 1024 * 1024 * 500;
        let child_stack = malloc(child_stack_space);
        let flags = CLONE_NEWIPC | CLONE_NEWNET | CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS;
        let child_pid = clone(
            child_function,
            child_stack.offset(child_stack_space as isize),
            flags | SIGCHLD,
            null_mut(),
        );
        if child_pid == -1 {
            printf(c"%s\n".as_ptr(), strerror(*__errno_location()));
        } else {
            println!("child pid: {}", child_pid);
        }
        wait(null_mut());
    }
    extern "C" fn child_function(_: *mut c_void) -> c_int {
        // 需在调用 pivot_root 前挂载 OverlayFS

        unsafe {
            mount(null(), c"/".as_ptr(), null(), MS_REC | MS_PRIVATE, null());
            // mount(
            //     c"/var/jdocker/runtime_dir/rootfs".as_ptr(),
            //     c"/var/jdocker/runtime_dir/rootfs".as_ptr(),
            //     null(),
            //     MS_REC | MS_BIND,
            //     null(),
            // );

            // std::fs::create_dir_all("/var/jdocker/runtime_dir/rootfs/.old_root").expect("Failed to create .old_root");
            let mut child = Command::new("mount")
                .arg("-t")
                .arg("overlay")
                .arg("overlay")
                .arg("-o")
                .arg("lowerdir=/var/jdocker/image_dir/rootfs,upperdir=/var/jdocker/containers_dir/rootfs,workdir=/var/jdocker/tmp_dir/rootfs")
                .arg("/var/jdocker/runtime_dir/rootfs")
                .spawn().expect("failed to spawn overlay overlay");
            let status = child.wait().expect("failed to wait on overlay child");
            println!("{}", status.code().expect("child exited with an error"));
        }
        let mut child2 = Command::new("mkdir")
            .arg("/var/jdocker/runtime_dir/rootfs/.old_root")
            .spawn().expect("failed to spawn overlay overlay");
        child2.wait().expect("failed to wait on overlay child");
        let x = pivot_root(
            "/var/jdocker/runtime_dir/rootfs",
            "/var/jdocker/runtime_dir/rootfs/.old_root",
        )
            .expect("err");
        let i = unsafe { chdir(c"/".as_ptr()) };
        unsafe { execlp(c"sh".as_ptr(), c"sh".as_ptr(), null::<c_void>()); }
        println!("ok");
        1
    }
}
